//this file is part of eMule
//Copyright (C)2002 Merkur ( merkur-@users.sourceforge.net / http://www.emule-project.net )
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

//#include "stdafx.h"
#include "wintypes.h"
#include "UploadQueue.h"
#include "ClientList.h"
#include "emule.h"
#include "otherfunctions.h"


CClientList::CClientList(){
}

CClientList::~CClientList(){
}

// xrmb : statsclientstatus
void CClientList::GetStatistics(uint32 &totalclient, int stats[], CMap<uint8, uint8, uint32, uint32> *clientStatus, CMap<uint16, uint16, uint32, uint32> *clientVersionEDonkey, CMap<uint16, uint16, uint32, uint32> *clientVersionEDonkeyHybrid, CMap<uint8, uint8, uint32, uint32> *clientVersionEMule){
	//if(clientStatus)		clientStatus->RemoveAll();
	totalclient = list.GetCount();
	if(clientVersionEDonkey)	clientVersionEDonkey->RemoveAll();
	if(clientVersionEMule)		clientVersionEMule->RemoveAll();
	POSITION pos1, pos2;

	for (int i=0;i<8;i++) stats[i]=0;

	for (pos1 = list.GetHeadPosition();( pos2 = pos1 ) != NULL;){
		list.GetNext(pos1);
		CUpDownClient* cur_client =	list.GetAt(pos2);
		
		switch (cur_client->GetClientSoft()) {
			case SO_UNKNOWN : stats[0]++;break;
			case SO_EDONKEY : 
				stats[1]++;
				if(clientVersionEDonkey)
					(*clientVersionEDonkey)[cur_client->GetVersion()]++;
				break;
			case SO_EDONKEYHYBRID : 
				stats[4]++;
				if(clientVersionEDonkeyHybrid)
					(*clientVersionEDonkeyHybrid)[cur_client->GetVersion()]++;
				break;
			case SO_EMULE   :
			case SO_OLDEMULE:
				stats[2]++;
				if(clientVersionEMule) {
					uint8 version = cur_client->GetMuleVersion();
					(*clientVersionEMule)[version]++;
				}
				break;
			case SO_CDONKEY : //Didn't get much time to test this "eMule Compatable" feature.
				stats[5]++;
				break;
			case SO_LMULE : 
				stats[6]++;
				break;
			case SO_MLDONKEY:
				stats[3]++;
				break;
			case SO_NEW_MLDONKEY:
				stats[7]++;
				break;
		}

		//if(clientStatus) (*clientStatus)[cur_client->GetDownloadState()]++;
	}
}


void CClientList::AddClient(CUpDownClient* toadd,bool bSkipDupTest){
	if ( !bSkipDupTest){
		if(list.Find(toadd))
			return;
	}
	list.AddTail(toadd);
}

void CClientList::RemoveClient(CUpDownClient* toremove){
	POSITION pos = list.Find(toremove);
	if (pos){
		//just to be sure...
		theApp.uploadqueue->RemoveFromUploadQueue(toremove);
		theApp.uploadqueue->RemoveFromWaitingQueue(toremove);
		theApp.downloadqueue->RemoveSource(toremove);
		list.RemoveAt(pos);
	}
}

void CClientList::DeleteAll(){
	theApp.uploadqueue->DeleteAll();
	theApp.downloadqueue->DeleteAll();
	POSITION pos1, pos2;
	for (pos1 = list.GetHeadPosition();( pos2 = pos1 ) != NULL;){
		list.GetNext(pos1);
		CUpDownClient* cur_client =	list.GetAt(pos2);
		list.RemoveAt(pos2);
		delete cur_client; // recursiv: this will call RemoveClient
	}
}

bool CClientList::AttachToAlreadyKnown(CUpDownClient** client, CClientReqSocket* sender){
	POSITION pos1, pos2;
	CUpDownClient* tocheck = (*client);
	for (pos1 = list.GetHeadPosition();( pos2 = pos1 ) != NULL;){
		list.GetNext(pos1);
		CUpDownClient* cur_client =	list.GetAt(pos2);
		if (tocheck->Compare(cur_client)){
			if (sender){
				if (cur_client->socket){
					cur_client->socket->client = 0;
					cur_client->socket->Safe_Delete();
				}
				cur_client->socket = sender;
				tocheck->socket = 0;
			}
			*client = 0;
			delete tocheck;
			*client = cur_client;
			return true;
		}
	}
	return false;
}

CUpDownClient* CClientList::FindClientByIP(uint32 clientip,uint16 port){
	POSITION pos1, pos2;
	for (pos1 = list.GetHeadPosition();( pos2 = pos1 ) != NULL;){
		list.GetNext(pos1);
		CUpDownClient* cur_client =	list.GetAt(pos2);
		if (cur_client->GetIP() == clientip && cur_client->GetUserPort() == port)
			return cur_client;
	}
	return 0;
}

CUpDownClient* CClientList::FindClientByUserHash(uchar* clienthash){
	POSITION pos1, pos2;
	for (pos1 = list.GetHeadPosition();( pos2 = pos1 ) != NULL;){
		list.GetNext(pos1);
		CUpDownClient* cur_client =	list.GetAt(pos2);
		if (memcmp(cur_client->GetUserHash() ,clienthash,16)  )
				return cur_client;
	}
	return 0;
}


void CClientList::Debug_SocketDeleted(CClientReqSocket* deleted){
	POSITION pos1, pos2;
	for (pos1 = list.GetHeadPosition();( pos2 = pos1 ) != NULL;){
		list.GetNext(pos1);
		CUpDownClient* cur_client =	list.GetAt(pos2);
#if 0
		if (!AfxIsValidAddress(cur_client, sizeof(CUpDownClient))) {
			AfxDebugBreak();
		}
		if (cur_client->socket == deleted){
			AfxDebugBreak();
		}
#endif
	}
}

bool CClientList::Debug_IsValidClient(CUpDownClient* tocheck){
	return list.Find(tocheck);
}


